package cn.jx.cjm.security.support;

import cn.jx.cjm.security.common.bean.CjmGrantedAuthority;
import cn.jx.cjm.security.common.bean.TokenUser;
import cn.jx.cjm.security.common.util.RouterUtils;
import cn.jx.cjm.security.common.util.SecurityUtils;
import cn.jx.cjm.security.entity.SysRolePermission;
import cn.jx.cjm.security.entity.SysUserRole;
import cn.jx.cjm.security.service.ISysPermissionService;
import cn.jx.cjm.security.service.ISysRolePermissionService;
import cn.jx.cjm.security.service.ISysRoleService;
import cn.jx.cjm.security.service.ISysUserRoleService;
import cn.jx.cjm.common.base.BaseSortChange;
import cn.jx.cjm.security.common.constant.SecurityCacheNameConstants;
import cn.jx.cjm.security.common.constant.SecuritySystemConstants;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import cn.jx.cjm.common.enums.BizExceptionEnum;
import cn.jx.cjm.common.exception.BizException;
import cn.jx.cjm.common.util.BeanUtils;
import cn.jx.cjm.security.dto.request.SysPermissionRequest;
import cn.jx.cjm.security.dto.response.SysPermissionResponse;
import cn.jx.cjm.security.entity.SysPermission;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 后台权限详情信息 业务处理层
 *
 * @author James Chen
 * @since 2019-12-16
 */

@Service
public class SysPermissionSupportService {


    @Autowired
    public ISysPermissionService sysPermissionService;
    @Autowired
    public ISysRolePermissionService sysRolePermissionService;
    @Autowired
    private ISysUserRoleService sysUserRoleService;
    @Autowired
    public SysPermissionSupportService sysPermissionSupportService;
    @Autowired
    public ISysRoleService sysRoleService;

    /**
     * 获取用户权限
     *
     * @return .
     */
    public List<SysPermission> getSysPermissionList() {
        List<SysPermission> sysPermissionList;
        TokenUser tokenUser = SecurityUtils.getSessionUser();
        if (SecuritySystemConstants.SUPER_ADMIN_ID.equals(tokenUser.getId())) {
            QueryWrapper<SysPermission> queryWrapper = new QueryWrapper<>();
            queryWrapper.orderByAsc("parent_id", "sort_by");
            sysPermissionList = sysPermissionService.list(queryWrapper);
        } else {
            List<CjmGrantedAuthority> authorities = tokenUser.getAuthorities();
            Set<Integer> sysRoleIdSet = authorities.stream().map(CjmGrantedAuthority::getSysRoleId).collect(Collectors.toSet());
            sysPermissionList = sysPermissionSupportService.getPermissionByRoles(sysRoleIdSet);
        }
        return sysPermissionList;
    }


    public List<SysPermissionResponse> list() {
        List<SysPermission> sysPermissionList = this.getSysPermissionList();
        if (!CollectionUtils.isEmpty(sysPermissionList)) {
            //拼装权限树
            RouterUtils routerUtils = new RouterUtils(sysPermissionList);
            return routerUtils.createSysPermissionList();
        } else {
            return new ArrayList<>();
        }
    }

    public SysPermissionResponse getOne(Integer id) {
        SysPermission sysPermission = sysPermissionService.getById(id);
        SysPermissionResponse result = new SysPermissionResponse();
        BeanUtils.copyPropertiesIgnoreNull(sysPermission, result);
        return result;
    }

    public void save(SysPermissionRequest request) {
        SysPermission sysPermission = new SysPermission();
        BeanUtils.copyPropertiesIgnoreNull(request, sysPermission);
        sysPermission.setRouterTitle(sysPermission.getAuthorityName());
        sysPermission.setCreateTime(LocalDateTime.now());
        sysPermissionService.save(sysPermission);
    }

    public void update(SysPermissionRequest request) {
        SysPermission sysPermission = new SysPermission();
        BeanUtils.copyPropertiesIgnoreNull(request, sysPermission);
        sysPermission.setRouterTitle(sysPermission.getAuthorityName());
        sysPermissionService.updateById(sysPermission);
    }

    @Transactional(rollbackFor = {BizException.class}, propagation = Propagation.REQUIRED)
    public void sort(BaseSortChange request) {
        SysPermission temp1 = new SysPermission();
        temp1.setId(request.getOneId());
        temp1.setSortBy(request.getTwoSortBy());
        SysPermission temp2 = new SysPermission();
        temp2.setId(request.getTwoId());
        temp2.setSortBy(request.getOneSortBy());
        sysPermissionService.updateById(temp1);
        sysPermissionService.updateById(temp2);

    }


    /**
     * 删除权限
     *
     * @param id 权限id
     */
    @Transactional(rollbackFor = {BizException.class}, propagation = Propagation.REQUIRED)
    @CacheEvict(cacheNames = SecurityCacheNameConstants.ROLE_PATH_LIST, allEntries = true)
    public void remove(Integer id) {
        List<SysPermission> sysPermissionList = sysPermissionService.list(null);
        RouterUtils routerUtils = new RouterUtils(sysPermissionList);
        Set<Integer> permissionIds = routerUtils.getPermissionIdTree(id);

        sysPermissionService.removeByIds(permissionIds);
        QueryWrapper<SysRolePermission> sysRolePermissionQueryWrapper = new QueryWrapper<>();
        sysRolePermissionQueryWrapper.in("sys_permission_id", permissionIds);
        sysRolePermissionService.remove(sysRolePermissionQueryWrapper);
    }

    /**
     * 获取多个角色权限
     *
     * @param sysRoleIds 角色id集合
     * @return .
     */
    public List<SysPermission> getPermissionByRoles(Collection<Integer> sysRoleIds) {
        List<SysPermission> sysPermissionList = new ArrayList<>();

        for (Integer sysRoleId : sysRoleIds) {
            //不用this , 因为this无法调起CacheAble
            Collection<SysPermission> sysPermissionListTemp = sysPermissionSupportService.getPermissionByRole(sysRoleId);
            if (!CollectionUtils.isEmpty(sysPermissionListTemp)) {
                sysPermissionList.addAll(sysPermissionListTemp);
            }
        }
        if (sysRoleIds.size() > 1 && !CollectionUtils.isEmpty(sysPermissionList)) {
            //若用户存在多个角色则进行去重处理
            sysPermissionList = sysPermissionList.stream().distinct().collect(Collectors.toList());
            sysPermissionList.sort(Comparator.comparing(SysPermission::getSortBy));
        }
        return sysPermissionList.stream().sorted((Comparator.comparing(SysPermission::getSortBy))).collect(Collectors.toList());
    }

    /**
     * 获取角色权限
     *
     * @param sysRoleId 角色id
     * @return .
     */
    @Cacheable(cacheNames = SecurityCacheNameConstants.ROLE_PATH_LIST, unless = "#result == null", key = "#sysRoleId.toString()")
    public Collection<SysPermission> getPermissionByRole(Integer sysRoleId) {
        //获取角色权限ID集合
        List<SysRolePermission> sysRolePermissionList = getRolePermissionByRole(sysRoleId);
        if (!CollectionUtils.isEmpty(sysRolePermissionList)) {
            //角色权限ID集合
            Set<Integer> sysPermissionIdSet = sysRolePermissionList.stream().map(SysRolePermission::getSysPermissionId).collect(Collectors.toSet());
            //角色权限
            return sysPermissionService.listByIds(sysPermissionIdSet);
        }

        return null;
    }

    /**
     * 通过角色ID查询角色-权限对应列表
     *
     * @param sysRoleId .
     * @return .
     */
    public List<SysRolePermission> getRolePermissionByRole(Integer sysRoleId) {
        //获取角色权限ID集合
        QueryWrapper<SysRolePermission> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("sys_role_id", sysRoleId);
        return sysRolePermissionService.list(queryWrapper);
    }


    /**
     * 删除角色权限
     *
     * @param sysRoleId 角色id
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void deleteRolePermissionByRole(Integer sysRoleId) {
        QueryWrapper<SysRolePermission> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("sys_role_id", sysRoleId);
        sysRolePermissionService.remove(queryWrapper);

        QueryWrapper<SysUserRole> sysUserRoleQueryWrapper = new QueryWrapper<>();
        sysUserRoleQueryWrapper.eq("sys_role_id", sysRoleId);
        sysUserRoleService.remove(sysUserRoleQueryWrapper);
    }


    /**
     * 保存角色权限对应信息
     *
     * @param sysRoleId     角色ID
     * @param permissionIds 权限ID集合
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void saveRolePermission(Integer sysRoleId, Collection<Integer> permissionIds) {
        List<SysPermission> sysPermissionList;
        TokenUser tokenUser = SecurityUtils.getSessionUser();
        if (SecuritySystemConstants.SUPER_ADMIN_ID.equals(tokenUser.getId())) {
            sysPermissionList = sysPermissionService.list(null);
        } else {
            List<CjmGrantedAuthority> authorities = tokenUser.getAuthorities();
            Set<Integer> sysRoleIdSet = authorities.stream().map(CjmGrantedAuthority::getSysRoleId).collect(Collectors.toSet());
            sysPermissionList = sysPermissionSupportService.getPermissionByRoles(sysRoleIdSet);
        }
        Set<Integer> userPermissionIds = sysPermissionList.stream().map(SysPermission::getId).collect(Collectors.toSet());
        QueryWrapper<SysRolePermission> rolePermissionQueryWrapper = new QueryWrapper<>();
        rolePermissionQueryWrapper.eq("sys_role_id", sysRoleId);
        sysRolePermissionService.remove(rolePermissionQueryWrapper);

        List<SysRolePermission> sysRolePermissionList = new ArrayList<>(permissionIds.size());
        for (Integer permissionId : permissionIds) {
            //不允许添加操作人员没有的权限
            if (!userPermissionIds.contains(permissionId)) {
                continue;
            }
            SysRolePermission sysRolePermission = new SysRolePermission();
            sysRolePermission.setSysRoleId(sysRoleId);
            sysRolePermission.setSysPermissionId(permissionId);
            sysRolePermissionList.add(sysRolePermission);
        }
        if (!sysRolePermissionService.saveBatch(sysRolePermissionList)) {
            throw new BizException(BizExceptionEnum.SAVE_ERROR);
        }
    }
}

